package com.dikeleakagedetection.myapplication.ui.ble

import android.bluetooth.BluetoothGattCharacteristic
import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import android.text.method.ScrollingMovementMethod
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.fragment.app.Fragment
import com.clj.fastble.BleManager
import com.clj.fastble.callback.BleIndicateCallback
import com.clj.fastble.callback.BleReadCallback
import com.clj.fastble.callback.BleWriteCallback
import com.clj.fastble.data.BleDevice
import com.clj.fastble.exception.BleException
import com.clj.fastble.utils.HexUtil
import com.dikeleakagedetection.myapplication.DikeLeakageDetectionApp
import com.dikeleakagedetection.myapplication.R
import com.dikeleakagedetection.myapplication.databinding.FragBleCharacterOpBinding

import java.util.*

class CharacteristicOperationFragment : Fragment() {

    companion object {
        private const val KEY_DATA_1 = "key_ble_device"
        private const val KEY_DATA_2 = "key_ble_device_service_charateristic"
        private const val KEY_DATA_3 = "key_charateristic_select_property"

        const val PROPERTY_READ = 1
        const val PROPERTY_WRITE = 2
        const val PROPERTY_WRITE_NO_RESPONSE = 3
        const val PROPERTY_NOTIFY = 4
        const val PROPERTY_INDICATE = 5

        fun newInstance(
            bluetoothGattCharacteristic: BluetoothGattCharacteristic,
            property: Int,
            bleDevice: BleDevice
        ): CharacteristicOperationFragment {
            val characteristicOperationFragment = CharacteristicOperationFragment()

            //使用Bundle封装数据
            val bundle = Bundle()
            bundle.putParcelable(KEY_DATA_1, bleDevice)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                bundle.putParcelable(KEY_DATA_2, bluetoothGattCharacteristic)
            }
            bundle.putInt(KEY_DATA_3, property)
            characteristicOperationFragment.arguments = bundle

            //即使fragment重构，也会通过反射的机制，把重新实例化的fragment设上参数title
            return characteristicOperationFragment
        }
    }

    private lateinit var viewModel: CharacteristicOperationViewModel

    private lateinit var binding: FragBleCharacterOpBinding

    private val childList: ArrayList<String> = ArrayList()


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragBleCharacterOpBinding.inflate(inflater, container, false)
        val view = binding.root

        // Inflate the layout for this fragment
        val bleDevice: BleDevice = arguments?.getParcelable(KEY_DATA_1)!!
        val characteristic: BluetoothGattCharacteristic? = arguments?.getParcelable(
            KEY_DATA_2
        )
        val charaProperty: Int = arguments?.getInt(KEY_DATA_3)!!

        binding.tbFragCharaOp.title = bleDevice.name
        binding.tbFragCharaOp.subtitle = "特征UUID：" + characteristic?.uuid

        layoutAdd(bleDevice, characteristic!!, charaProperty)

        return view
    }

    private fun layoutAdd(
        bleDevice: BleDevice,
        characteristic: BluetoothGattCharacteristic,
        charaProperty: Int
    ) {
        val child: String = characteristic.uuid.toString() + charaProperty

        for (i in 0 until binding.lyFragCharacterOp.childCount) {
            binding.lyFragCharacterOp.getChildAt(i).visibility = View.GONE
        }
        if (childList.contains(child)) {
            binding.lyFragCharacterOp.findViewWithTag<View>(
                bleDevice.key + characteristic.uuid.toString() + charaProperty
            ).visibility = View.VISIBLE
        } else {
            childList.add(child)

            val view: View =
                LayoutInflater.from(activity).inflate(R.layout.ly_frag_ble_charac_op, null)
            view.tag = bleDevice.key + characteristic.uuid.toString() + charaProperty
            val lyAdd = view.findViewById<View>(R.id.ly_add) as LinearLayout
            val tvTitle = view.findViewById<View>(R.id.tv_title_frag_character_op) as TextView
            tvTitle.text = (characteristic.uuid
                .toString() + activity?.getString(R.string.data_changed))
            val tvCharaOperationShow =
                view.findViewById<View>(R.id.tv_show_frag_character_op) as TextView
            tvCharaOperationShow.movementMethod = ScrollingMovementMethod.getInstance()

            when (charaProperty) {
                PROPERTY_READ -> {
                    val viewAdd: View = LayoutInflater.from(activity)
                        .inflate(R.layout.ly_button_frag_ble_char_op, null)
                    val btn = viewAdd.findViewById<View>(R.id.btn) as Button
                    btn.text = activity?.getString(R.string.read)
                    btn.setOnClickListener {
                        BleManager.getInstance().read(
                            bleDevice,
                            characteristic.service.uuid.toString(),
                            characteristic.uuid.toString(),
                            object : BleReadCallback() {
                                override fun onReadSuccess(data: ByteArray) {
                                    runOnUiThread {
                                        addText(
                                            tvCharaOperationShow,
                                            HexUtil.formatHexString(data, true)
                                        )
                                    }
                                }

                                override fun onReadFailure(exception: BleException) {
                                    runOnUiThread {
                                        addText(
                                            tvCharaOperationShow,
                                            exception.toString()
                                        )
                                    }
                                }
                            })
                    }
                    lyAdd.addView(viewAdd)
                }
                PROPERTY_WRITE -> {
                    val viewAdd: View = LayoutInflater.from(activity)
                        .inflate(R.layout.ly_et_frag_character_op, null)
                    val et = viewAdd.findViewById<View>(R.id.et) as EditText
                    val btn = viewAdd.findViewById<View>(R.id.btn) as Button
                    btn.text = activity?.getString(R.string.write)
                    btn.setOnClickListener(View.OnClickListener {
                        val hex = et.text.toString()
                        if (TextUtils.isEmpty(hex)) {
                            return@OnClickListener
                        }
                        BleManager.getInstance().write(
                            bleDevice,
                            characteristic.service.uuid.toString(),
                            characteristic.uuid.toString(),
                            HexUtil.hexStringToBytes(hex),
                            object : BleWriteCallback() {
                                override fun onWriteSuccess(
                                    current: Int,
                                    total: Int,
                                    justWrite: ByteArray
                                ) {
                                    runOnUiThread {
                                        addText(
                                            tvCharaOperationShow,
                                            "write success, current: " + current
                                                    + " total: " + total
                                                    + " justWrite: " + HexUtil.formatHexString(
                                                justWrite,
                                                true
                                            )
                                        )
                                    }
                                }

                                override fun onWriteFailure(exception: BleException) {
                                    runOnUiThread {
                                        addText(
                                            tvCharaOperationShow,
                                            exception.toString()
                                        )
                                    }
                                }
                            })
                    })
                    lyAdd.addView(viewAdd)
                }
                PROPERTY_WRITE_NO_RESPONSE -> {
                    val viewAdd: View = LayoutInflater.from(activity)
                        .inflate(R.layout.ly_et_frag_character_op, null)
                    val et = viewAdd.findViewById<View>(R.id.et) as EditText
                    val btn = viewAdd.findViewById<View>(R.id.btn) as Button
                    btn.text = activity?.getString(R.string.write)
                    btn.setOnClickListener(View.OnClickListener {
                        val hex = et.text.toString()
                        if (TextUtils.isEmpty(hex)) {
                            return@OnClickListener
                        }
                        BleManager.getInstance().write(
                            bleDevice,
                            characteristic.service.uuid.toString(),
                            characteristic.uuid.toString(),
                            HexUtil.hexStringToBytes(hex),
                            object : BleWriteCallback() {
                                override fun onWriteSuccess(
                                    current: Int,
                                    total: Int,
                                    justWrite: ByteArray
                                ) {
                                    runOnUiThread {
                                        addText(
                                            tvCharaOperationShow,
                                            "write success, current: " + current
                                                    + " total: " + total
                                                    + " justWrite: " + HexUtil.formatHexString(
                                                justWrite,
                                                true
                                            )
                                        )
                                    }
                                }

                                override fun onWriteFailure(exception: BleException) {
                                    runOnUiThread {
                                        addText(
                                            tvCharaOperationShow,
                                            exception.toString()
                                        )
                                    }
                                }
                            })
                    })
                    lyAdd.addView(viewAdd)
                }
                PROPERTY_NOTIFY -> {
                    val viewAdd: View = LayoutInflater.from(activity)
                        .inflate(R.layout.ly_button_frag_ble_char_op, null)
                    val btn = viewAdd.findViewById<View>(R.id.btn) as Button
                    btn.text = activity?.getString(R.string.open_notification)
                    btn.setOnClickListener {
                        DikeLeakageDetectionApp.currentBleDevice.bleDevice = bleDevice
                        DikeLeakageDetectionApp.currentBleDevice.characteristic = characteristic

                        if (btn.text.toString() == activity?.getString(R.string.open_notification)) {
                            btn.text = activity?.getString(R.string.close_notification)
                            /*BleManager.getInstance().notify(
                                bleDevice,
                                characteristic.service.uuid.toString(),
                                characteristic.uuid.toString(),
                                object : BleNotifyCallback() {
                                    override fun onNotifySuccess() {

                                    }

                                    override fun onNotifyFailure(exception: BleException) {
                                        runOnUiThread {
                                            addText(
                                                tvCharaOperationShow,
                                                exception.toString()
                                            )
                                        }
                                    }

                                    override fun onCharacteristicChanged(data: ByteArray) {
                                        runOnUiThread {
                                            val string16 =
                                                HexUtil.formatHexString(
                                                    characteristic.value,
                                                    false
                                                )
                                            val s = String(HexUtils.hex2Bytes(string16))
                                            addText(tvCharaOperationShow, s)
                                        }
                                    }
                                })*/
                        } else {
                            btn.text = activity?.getString(R.string.open_notification)
                            BleManager.getInstance().stopNotify(
                                bleDevice,
                                characteristic.service.uuid.toString(),
                                characteristic.uuid.toString()
                            )
                        }
                    }
                    lyAdd.addView(viewAdd)
                }
                PROPERTY_INDICATE -> {
                    val viewAdd: View = LayoutInflater.from(activity)
                        .inflate(R.layout.ly_button_frag_ble_char_op, null)
                    val btn = viewAdd.findViewById<View>(R.id.btn) as Button
                    btn.text = activity?.getString(R.string.open_notification)
                    btn.setOnClickListener {
                        if (btn.text.toString() == activity?.getString(R.string.open_notification)) {
                            btn.text = activity?.getString(R.string.close_notification)
                            BleManager.getInstance().indicate(
                                bleDevice,
                                characteristic.service.uuid.toString(),
                                characteristic.uuid.toString(),
                                object : BleIndicateCallback() {
                                    override fun onIndicateSuccess() {
                                        runOnUiThread {
                                            addText(
                                                tvCharaOperationShow,
                                                "indicate success"
                                            )
                                        }
                                    }

                                    override fun onIndicateFailure(exception: BleException) {
                                        runOnUiThread {
                                            addText(
                                                tvCharaOperationShow,
                                                exception.toString()
                                            )
                                        }
                                    }

                                    override fun onCharacteristicChanged(data: ByteArray) {
                                        runOnUiThread {
                                            addText(
                                                tvCharaOperationShow,
                                                HexUtil.formatHexString(
                                                    characteristic.value,
                                                    true
                                                )
                                            )
                                        }
                                    }
                                })
                        } else {
                            btn.text = activity?.getString(R.string.open_notification)
                            BleManager.getInstance().stopIndicate(
                                bleDevice,
                                characteristic.service.uuid.toString(),
                                characteristic.uuid.toString()
                            )
                        }
                    }
                    lyAdd.addView(viewAdd)
                }
            }

            binding.lyFragCharacterOp.addView(view)
        }

    }

    fun runOnUiThread(runnable: Runnable) {
        if (isAdded && activity != null) activity?.runOnUiThread(runnable)
    }

    fun addText(textView: TextView, content: String) {
        textView.append(content)
        textView.append("\n")
        val offset = textView.lineCount * textView.lineHeight
        if (offset > textView.height) {
            textView.scrollTo(0, offset - textView.height)
        }
    }

}


